import {Layout, MarkdownRender, Typography} from "@douyinfe/semi-ui";
import React, {JSX, useEffect, useRef, useState} from "react";
import ConversationInput from "./conversation/ConversationInput.tsx";
import {IconAvatar} from "@douyinfe/semi-icons-lab";
import {UserOutlined} from "@ant-design/icons";
import {Flex, GetProp} from "antd";
import {Bubble, useXAgent, useXChat} from "@ant-design/x";
import {
    addMessageToConversation,
    getConversationMessages, getNowConversationKey,
    Message,
    UserType
} from "../../../api/storage/ApiConversation.ts";
import {aiStreamConversation} from "../../../api/ApiAIChat.ts";
import {MessageInfo} from "@ant-design/x/es/use-x-chat";

const ERROR_MESSAGE = "AI分析失败，请重试！"
export const KEY_REQUEST_MSG = "onRequestMessage"
//将本地的消息转化为XChat的消息流
const convertMessages = (messages: Message[]) => {
    return messages.map((message, index) => {
        let role: string;
        if (message.role === UserType.User) {
            role = "local";
        } else if (message.role === UserType.AI) {
            role = "ai";
        } else {
            role = message.role;
        }
        return {
            id: index,
            message: message.content,
            status: role
        };
    });
}
//两个角色一个是AI一个是用户
const roles: GetProp<typeof Bubble.List, 'roles'> = {
    ai: {
        placement: 'start',
        avatar: {icon: <IconAvatar style={{fontSize: 36}}/>, style: {background: '#fde3cf'}},
        style: {
            maxWidth: 600,
        },
    },
    local: {
        placement: 'end',
        avatar: {icon: <UserOutlined/>, style: {background: '#87d068'}},
    },
};

const Conversation = (props: { style?: React.CSSProperties, change: boolean }) => {
    //引入Footer用来放Input输入框，Content放聊天组件
    const {Footer, Content} = Layout;
    //输入框Input的内容
    const [content, setContent] = React.useState('');
    const contentRef = useRef<any>(null);
    //动态设置高度
    const [height, setHeight] = useState(0);
    //获取当前会话key
    const conversationKey = getNowConversationKey()!
    // Agent for request
    const [agent] = useXAgent({
        request: async ({message}, {onSuccess, onError, onUpdate}) => {
            //如果消息是正常的
            if (message) {
                let compose = ""
                //添加用户的消息到对话中
                addMessageToConversation({role: UserType.User, content: message});
                const onSuccessCallback = (result: Message) => {
                    //结果正常，就添加到对话中
                    addMessageToConversation(result);
                    compose = ""
                    onSuccess(result.content)
                }
                const onErrorCallback = (error: Error) => {
                    //结果不正常，就添加到对话中，并设置为Error类型
                    addMessageToConversation({role: UserType.Error, content: ERROR_MESSAGE});
                    onError(error);
                }
                const onUpdateCallback = (message: string) => {
                    compose = compose + message
                    onUpdate(compose);
                }
                await aiStreamConversation(getConversationMessages(), onSuccessCallback, onErrorCallback, onUpdateCallback)
            }
        },
    });
    useEffect(() => {
        const currentContent = contentRef.current;
        //新建大小变化观察
        const observer = new ResizeObserver((entries) => {
            const {height} = entries[0].contentRect;
            //减去两个padding
            setHeight(height - 40);
        });
        if (currentContent) {
            observer.observe(currentContent);
        }
        return () => {
            if (currentContent) {
                //移除观察
                observer.unobserve(currentContent);
            }
        };

    }, []);
    // 获取到他的设置Api
    const {onRequest, messages, setMessages} = useXChat({
            agent,
            requestPlaceholder: 'AI生成中...',
            requestFallback: ERROR_MESSAGE
        },
    );
    const preHandleMessages = (messages: MessageInfo<string>[]) => {
        return messages.filter((msg) => (
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-expect-error
            msg.status != UserType.System
        ))
    }
    useEffect(() => {
        // 从本地储存中获取历史消息
        const msgList = getConversationMessages();
        //这里会报错但是不用管
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-expect-error
        setMessages(convertMessages(msgList))
        const onRequestMsg = localStorage.getItem(KEY_REQUEST_MSG)
        if (onRequestMsg) {
            onRequest(onRequestMsg);
            localStorage.removeItem(KEY_REQUEST_MSG);
        }
    }, [props.change, setMessages, conversationKey, onRequest]);
    const components: { [key: string]: (props: { children: string }) => JSX.Element } = {}
    components['h1'] = ({children}) => <Typography.Title heading={1}
                                                         style={{fontSize: 18}}>{children}</Typography.Title>
    components['h2'] = ({children}) => <Typography.Title heading={2}
                                                         style={{fontSize: 16}}>{children}</Typography.Title>
    components['h3'] = ({children}) => <Typography.Title heading={3}
                                                         style={{fontSize: 14}}>{children}</Typography.Title>
    components['h4'] = ({children}) => <Typography.Title heading={4}
                                                         style={{fontSize: 12}}>{children}</Typography.Title>
    components['h5'] = ({children}) => <Typography.Title heading={5}
                                                         style={{fontSize: 10}}>{children}</Typography.Title>
    return (
        <div style={props.style}>
            <Layout style={props.style}>
                <Content style={{height: "100%"}}>
                    <div ref={contentRef} style={{height: "100%"}}>
                        <Flex vertical gap="middle">
                            {//如果这个key有效就显示聊天区域
                                conversationKey !== "" ? (<Bubble.List
                                    roles={roles}
                                    autoScroll={true}
                                    style={{
                                        height: height,
                                        scrollbarColor: "var(--semi-color-text-2) transparent",
                                        padding: 20,
                                    }}
                                    items={preHandleMessages(messages).map(({id, message, status}) => (
                                        {
                                            key: id,
                                            role: status === 'local' ? 'local' : 'ai',
                                            content: <MarkdownRender components={components} raw={message}/>,
                                        }))}
                                />) : (<></>)}
                        </Flex>
                    </div>
                </Content>
                <Footer style={{margin: 12}}>
                    <ConversationInput loading={agent.isRequesting()}
                                       value={content}
                                       setValue={setContent}
                                       onSubmit={(nextContent) => {
                                           //防止回车键单独把 / 发送出去
                                           if (nextContent != "/") {
                                               onRequest(nextContent);
                                               setContent('');
                                           }
                                       }}
                                       conversationKey={conversationKey}
                    />
                </Footer>
            </Layout>
        </div>)
}
export default Conversation